/*
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2019年1月7日
 */

package com.massyframework.beanskin.license.signature.ras;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import com.massyframework.beanskin.service.crypto.RSAKeyReader;
import com.massyframework.beanskin.util.IOUtils;

import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

/**
 * {@link BCRSAKeyReader} 提供从文件中加载RSA密钥的实现
 */
public final class BCRSAKeyReader implements RSAKeyReader {

	static {
		Security.addProvider(new BouncyCastleProvider());
	}
	
    /**
     * 构造方法
     */
    public BCRSAKeyReader(){
    	
    }

    /**
     * 从<code>privateKey</code>提取私钥字符串
     *
     * @param privateKey {@link PrivateKey}
     * @return {@link String}
     */
    @Override
    public String getString(PrivateKey privateKey) throws IOException {
        byte[] privBytes = privateKey.getEncoded();
        PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);
        ASN1Encodable encodable = pkInfo.parsePrivateKey();
        ASN1Primitive primitive = encodable.toASN1Primitive();
        privBytes = primitive.getEncoded(); // pkcs1私钥

        String name = "RSA PRIVATE KEY";
        PemObject pemObject = new PemObject(name, privBytes);
        StringWriter stringWriter = new StringWriter();
        PemWriter pemWriter = new PemWriter(stringWriter);
        try {
            pemWriter.writeObject(pemObject);
        } finally {
            IOUtils.close(pemWriter);
        }
        return stringWriter.toString();
    }

    /**
     * 从<code>publicKey</code>提取公钥字符串
     *
     * @param publicKey {@link PublicKey}
     * @return {@link String}
     */
    @Override
    public String getString(PublicKey publicKey) throws IOException {
        byte[] pubBytes = publicKey.getEncoded();
        String name = "PUBLIC KEY";
        PemObject pemObject = new PemObject(name, pubBytes);
        StringWriter stringWriter = new StringWriter();
        PemWriter pemWriter = new PemWriter(stringWriter);
        try {
            pemWriter.writeObject(pemObject);
        } finally {
            IOUtils.close(pemWriter);
        }
        return stringWriter.toString();
    }
    
    

    @Override
	public PrivateKey getPrivateKey(KeyStore keystore, String alias, char[] keyPass)
			throws UnrecoverableKeyException, NoSuchAlgorithmException, InvalidKeyException, 
				CertificateException, KeyStoreException {
    	Key key = keystore.getKey(alias, keyPass);
        if (key == null) {
            throw new InvalidKeyException("cannot load key from keystore, may be key[\"" +
                    alias + "\"]  is not exists, please check it.");
        }
		return (PrivateKey)key;
	}
    
    @Override
	public KeyPair getKeyPair(KeyStore keystore, String alias, char[] keyPass) throws UnrecoverableKeyException,
			NoSuchAlgorithmException, InvalidKeyException, CertificateException, KeyStoreException {
	    Key key = keystore.getKey(alias, keyPass);
	    if (key instanceof PrivateKey) {
            Certificate cert = keystore.getCertificate(alias);
            PublicKey publicKey = cert.getPublicKey();
            return new KeyPair(publicKey, (PrivateKey)key);
	    }
        return null;
	}

	@Override
	public X509Certificate getX509Certificate(KeyStore keystore, String alias)
			throws KeyStoreException {
		Certificate cert =  keystore.getCertificate(alias);
		return cert == null ? null : (cert instanceof X509Certificate? (X509Certificate)cert : null);
	}
	
	
    /**
     * 从<Code>file</Code>中加载x509证书
     *
     * @param file {@link File}, cer证书文件
     * @return {@link X509Certificate}
     */
    @Override
    public X509Certificate loadX509Certificate(File file)
            throws IOException, NoSuchProviderException, CertificateException {
        this.checkFile(file);
        X509Certificate result = null;
        FileInputStream input = null;
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
            input = new FileInputStream(file);
            result = (X509Certificate) certificateFactory.generateCertificate(input);
        }finally {
            IOUtils.close(input);
        }
        return result;
    }
    
    

    @Override
	public KeyStore loadKeyStore(File keyStoreFile, char[] storePass)
			throws KeyStoreException, IOException, NoSuchProviderException, CertificateException, NoSuchAlgorithmException {
    	this.checkFile(keyStoreFile);
		KeyStore result = KeyStore.getInstance("PKCS12", "BC");
		result.load(new FileInputStream(keyStoreFile), storePass);
		return result;
	}

	/**
     * 检查文件
     * @param file {@link  File}
     * @throws FileNotFoundException 文件不存在或者文件以目录方式存在时，抛出例外
     */
    protected void checkFile(File file) throws FileNotFoundException {
        if (!file.exists()){
            throw new FileNotFoundException("cannot found cer file: " + file.getPath() + ".");
        }
        if (file.isDirectory()){
            throw new FileNotFoundException( file.getName() + " is not a file.");
        }
    }

    @Override
    public String toString() {
        return "BCRSAKeyReader";
    }
}
